package com.vf.cloud.rendering.server.relay.server;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import com.jfinal.kit.StrKit;
import com.vf.cloud.common.pool.ProssPool;
import com.vf.cloud.rendering.common.constant.Cache;
import com.vf.cloud.rendering.common.constant.SoftPath;

import lombok.extern.slf4j.Slf4j;

/**
 * 中继服务
 * 
 * @author love
 *
 */
@Slf4j
public class TurnServer implements Runnable {

	@Override
	public void run() {
		String trurnPid = ProssPool.getPid(Cache.relay.getTurnPort() + "");
		if (!StrKit.isBlank(trurnPid)) {
			log.info("TUNServer >>> 正在运行.");
		} else {
			if (!writeConfig()) {
				log.error("TUNServer >>> 启动失败>> 生成配置失败.");
				return;
			}
			String cmd = String.format(
					" Powershell.exe -WindowStyle Hidden -executionpolicy unrestricted -File %s/Relay/Start_AWS_TURNServer.ps1",
					SoftPath.path);
			int status = executeCmd(cmd);

			if (0 != status) {
				log.error("TUNServer >>> 启动失败>> 执行命令失败:" + cmd);
				return;
			}
			log.info("TUNServer >>> 正在运行.");
		}
	}

	public void stop() {
		if (!genTUNServerStopBat()) {
			log.error("TUNServer生成停止bat文件失败，请联系管理员.");
			return;
		}
		int status = executeCmd(String.format("%s/Relay/Stop_TURNServe.bat", SoftPath.path));
		File f = new File(String.format("%s/Relay/Stop_TURNServe.bat", SoftPath.path));
		if (0 != status) {
			log.error("停止TUNServer失败，请联系管理员.");
			f.delete();
			return;
		}
		f.delete();
		log.info("STUNServer >>> 已停止运行.");
	}

	private int executeCmd(String command) {
		try {
			Runtime runtime = Runtime.getRuntime();
			Process process = runtime.exec(command);
			new Thread(new ConsoleThread(new BufferedReader(new InputStreamReader(process.getInputStream(), "GBK"))))
					.start();
			return process.waitFor();
		} catch (InterruptedException | IOException e) {
		}
		return -1;
	}

	class ConsoleThread implements Runnable {
		private BufferedReader bfr = null;

		public ConsoleThread(BufferedReader bfr) {
			this.bfr = bfr;
		}

		@Override
		public void run() {
			String line = null;
			try {
				while ((line = bfr.readLine()) != null) {
					log.info(line);
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	/**
	 * 写入配置文件
	 */
	public boolean writeConfig() {
		String bas = "function AddUser{\r\n" + "    param(\r\n" + "    $realm,\r\n" + "    $user, \r\n"
				+ "    $pass,\r\n" + "    $auth_file,\r\n" + "    [switch]$append)\r\n" + "\r\n"
				+ "    $md5 = new-object -TypeName System.Security.Cryptography.MD5CryptoServiceProvider\r\n"
				+ "    $utf8 = new-object -TypeName System.Text.UTF8Encoding\r\n"
				+ "    $hash = [System.BitConverter]::ToString($md5.ComputeHash($utf8.GetBytes(\"$user\" + \":$realm\" + \":$pass\")))\r\n"
				+ "    $hash = $hash.ToLower() -replace '-', ''\r\n" + "\r\n" + "    if($append){\r\n"
				+ "        \"$user=$hash\" | Out-File -FilePath $auth_file -Append -Encoding ascii\r\n"
				+ "    } else {\r\n" + "        \"$user=$hash\" | Out-File -FilePath $auth_file -Encoding ascii\r\n"
				+ "    }\r\n" + "\r\n" + "}\r\n" + "";
		BufferedWriter out = null;
		try {
			File f = new File(String.format("%s/Relay/Start_AWS_TURNServer.ps1", SoftPath.path));
			if (f.exists()) {
				f.delete();
			}

			out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(f, true)));
			out.write(bas + "\r\n");
			out.write(String.format("$LocalIp = \"%s\"", Cache.relay.getIp()) + "\r\n");
			out.write("Write-Output \"Private IP: $LocalIp\"\r\n");
			out.write("$AuthFile = \"turnserver_auth.txt\"\r\n");
			out.write("$Realm = \"PixelStreaming\"\r\n");
			out.write(String.format("$ProcessExe = \"%s/Relay/turnserver.exe\"", SoftPath.path) + "\r\n");
			out.write(String.format("$Arguments = \"0.0.0.0:%s $LocalIp $Realm $AuthFile\"", Cache.relay.getTurnPort())
					+ "\r\n");
			out.write(String.format("$TurnUsername = \"%s\"", "%s",Cache.relay.getUsername()) + "\r\n");
			out.write(String.format("$TurnPassword = \"%s\"", "%s",Cache.relay.getPassword()) + "\r\n");

			out.write("AddUser $Realm $TurnUsername $TurnPassword $AuthFile\r\n");
			out.write("Write-Output \"Running: $ProcessExe $Arguments\"\r\n");
			out.write("Start-Process -FilePath $ProcessExe -ArgumentList $Arguments -WindowStyle Hidden \r\n");
			try {
				out.close();
			} catch (IOException e) {
			}
			return true;
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				out.close();
			} catch (IOException e) {
			}
		}
		return false;
	}

	public boolean genStunserverStartBat() {
		BufferedWriter out = null;
		try {
			try {
				File f = new File(String.format("%s/Relay/Start_STUNServer.bat", SoftPath.path));
				if (f.exists()) {
					f.delete();
				}
				out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(f, true)));
				out.write("@echo off \r\n");
				out.write(String.format("%s \r\n", SoftPath.path.substring(0, 2)));
				out.write(String.format("cd %s/Relay \r\n", SoftPath.path));
				out.write(String.format("stunserver.exe 0.0.0.0:%s \r\n", Cache.relay.getStunPort()));
				out.write("echo \"startStunserver1999\" \r\n");
				out.write("exit");
				out.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
			return true;
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				if (out != null)
					out.close();
			} catch (IOException e) {
			}
		}
		return false;
	}

	public boolean genTUNServerStopBat() {
		BufferedWriter out = null;
		try {
			try {
				File f = new File(String.format("%s/Relay/Stop_TURNServe.bat", SoftPath.path));
				if (f.exists()) {
					f.delete();
				}
				out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(f, true)));
				out.write("@echo off \r\n");
				out.write(String.format("%s \r\n", SoftPath.path.substring(0, 2)));
				out.write(String.format("cd %s/Relay \r\n", SoftPath.path));
				out.write("tasklist | findstr /i \"turnserver.exe\" \r\n");
				out.write("@echo \"turnserver is running, stopping...\"  \r\n");
				out.write("TASKKILL /F /IM turnserver.exe /T \r\n");
				out.write("echo \"stopTurnserver1999\" \r\n");
				out.write("exit");
				out.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
			return true;
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				if (out != null)
					out.close();
			} catch (IOException e) {
			}
		}
		return false;
	}

	public void restart() {
		ProssPool.kill("TurnServer");
		ProssPool.kill("StunServer");
		run();
	}

	public void stop(String stunPort, String turnPort) {
		String stun = ProssPool.getPid(stunPort);
		String turn = ProssPool.getPid(turnPort);

		System.out.println(">>>>>>>>>>>stun=" + stun);
		System.out.println(">>>>>>>>>>>turn=" + turn);

		ProssPool.kill("StunServer", stun);
		ProssPool.kill("TurnServer", turn);

		ProssPool.kill("TurnServer");
		ProssPool.kill("StunServer");
	}

}
